package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	//setCounterNegative()     //计数器设置为负值
	//timesOfDoneMoreThanCounter() //调用 Done 方法的次数过多，超过了 WaitGroup 的计数值
	//badTimeForExecute() //原则就是，等所有的 Add 方法调用之后再调用 Wait
	errorTimeForReuse() //前一个 Wait 还没结束就重用 WaitGroup
}

func setCounterNegative() {
	var wg sync.WaitGroup
	wg.Add(10)

	wg.Add(-10) //将-10作为参数调用Add，计数值被设置为0

	wg.Add(-1) //将-1作为参数调用Add，如果加上-1计数值就会变为负数。这是不对的，所以会触发panic
}
func timesOfDoneMoreThanCounter() {
	var wg sync.WaitGroup
	wg.Add(1)

	wg.Done()

	wg.Done()
}

func badTimeForExecute() {
	var wg sync.WaitGroup
	go doSomething(100, &wg) // 启动第一个goroutine
	go doSomething(110, &wg) // 启动第二个goroutine
	go doSomething(120, &wg) // 启动第三个goroutine
	go doSomething(130, &wg) // 启动第四个goroutine

	wg.Wait() // 主goroutine等待完成
	fmt.Println("Done")
}

func doSomething(millisecs time.Duration, wg *sync.WaitGroup) {
	duration := millisecs * time.Millisecond
	time.Sleep(duration) // 故意sleep一段时间

	wg.Add(1)
	fmt.Println("后台执行, duration:", duration)
	wg.Done()
}

func errorTimeForReuse() {
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		time.Sleep(time.Millisecond)
		wg.Done() // 计数器减1
		wg.Add(1) // 计数值加1
	}()
	wg.Wait() // 主goroutine等待，有可能和第7行并发执行
}
